/* 
 * File:   Socket.cpp
 * Author: Lance
 * 
 * Created on September 13, 2012, 9:09 PM
 */


#include <sstream>

#include "Socket.h"

Socket::Socket(string host, int port)
{
	this->port = port;
	ipAddress = Socket::dns(host);
		
	memset(&server,0,sizeof(server));
	server.sin_family = AF_INET;
	server.sin_port = htons(port);
	
	if (!inet_aton(ipAddress ,&server.sin_addr)) {
		printf("inet_addr() conversion error\n");
		exit(-1);
	}
	  // create socket
	s_handle = socket(PF_INET,SOCK_STREAM,0);
	if (s_handle < 0) {
		perror("socket");
		exit(-1);
	}
	  // connect to server
	if (connect(s_handle,(const struct sockaddr *)&server,sizeof(server)) < 0) {
		perror("connect");
		exit(-1);
	}
}

Socket::Socket(const Socket& orig) {
}

Socket::~Socket() {
}

void Socket::sendRequest(HTTPRequest * request)
{
	string command = request->str();
	//Send the HTTP request to the server we are connected to
	const char *ptr = command.c_str();
	int nwritten, nleft;
	nleft = command.length();
	while (nleft) {
		if ((nwritten = send(s_handle, ptr, nleft, 0)) < 0) {
		if (errno == EINTR) {
			  // the socket call was interrupted -- try again
			nwritten = 0;
		} else {
			  // an error occurred, so break out
			perror("write");
			break;
		}
		} else if (nwritten == 0) {
		  // the socket is closed
		break;
		}
		nleft -= nwritten;
		ptr += nwritten;
	}
	

}

HTTPResponse * Socket::getResponseHeader()
{
	HTTPResponse * response = new HTTPResponse();
	char *buf = (char *) calloc(1000,sizeof(char));
	string responseStr("");
	int nread = 0;
	int amount = 0;
	do
	{
		memset(buf, 0, 1000);
		nread = recv(s_handle,buf,1000,0);
		responseStr.append(buf,nread);
		amount += nread;
	} while(noBlankLine(responseStr));
	response->parse(responseStr);
		
	if(atoi(response->code().c_str()) > 200)
	{
//		cout << response->phrase() << endl;
	}
	
	amount = responseStr.length() - (responseStr.find("\r\n\r\n")+4);
	responseStr = responseStr.substr(responseStr.find("\r\n\r\n") +4, amount);
	
	response->header("ResponseMessage", responseStr);
	return response;
}

HTTPResponse * Socket::getResponse()
{
	HTTPResponse * response = getResponseHeader();
	char *buf = (char *) calloc(1000,sizeof(char));
	
	string responseStr = response->header("ResponseMessage");
	int contentLength = atoi(response->header("Content-Length").c_str());
	int amount = responseStr.length();
	while(amount < contentLength)
	{
		memset(buf, 0, 1000);
		int nread = recv(s_handle,buf,1000,0);
		if(nread < 0)
		{
			if (errno == EINTR)
				continue;
			else
				break;
		}
		else if (nread == 0)
		{
			break;
		}
		responseStr.append(buf, nread);
		amount += nread;
	}

	response->header("ResponseMessage", responseStr);
	
	return response;
}

void Socket::closeSocket()
{
	close(s_handle);
}

const char * Socket::dns(string host)
{
//	cout << host << endl;
    struct hostent *hostEntry;
    hostEntry = gethostbyname(host.c_str());
    if (!hostEntry) {
        cout << "No such host name: " << host << endl;
        exit(-1);
    }

    int i = 0;
    while (hostEntry->h_aliases[i] != NULL) {
        i++;
    }

    i = 0;
    while (hostEntry->h_addr_list[i] != NULL) {
        i++;
    }
	
	const char * ip = inet_ntoa(*(struct in_addr *)hostEntry->h_addr_list[0]);
	return ip;
}

bool Socket::noBlankLine(string response)
{	
	return response.find("\r\n\r\n") == string::npos;
}

